home *** CD-ROM | disk | FTP | other *** search
- /*
- CPP V5 -- Token parsing routines.
-
- source: tok.c
- started: October 7, 1985
- version: May 26, 1988; July 21, 1988
-
- Written by Edward K. Ream.
- This software is in the public domain.
-
- See the read.me file for disclaimer and other information.
- */
-
- #include "cpp.h"
-
- /* Declare internal variables and routines. */
- static int is_base_digit (int);
- static void scan_number (int);
- static en_tokens t_int (void);
-
- /*
- Return >= 0 if ch is a digit in the indicated base.
- Otherwise, return -1.
- */
- static int
- is_base_digit(base)
- int base;
- {
- TRACECH("is_base_digit");
-
- if (ch >= '0' && ch <= '9') {
- RETURN_INT("is_base_digit", ch - '0');
- }
- else if (base != 16) {
- RETURN_INT("is_base_digit", -1);
- }
- else if (ch >= 'a' && ch <= 'f') {
- RETURN_INT("is_base_digit", ch - 'a' + 10);
- }
- else if (ch >= 'A' && ch <= 'F') {
- RETURN_INT("is_base_digit", ch - 'A' + 10);
- }
- else {
- RETURN_INT("is_base_digit", -1);
- }
- }
-
- /*
- Get value of a string of digits into t_value.
- Continue until a non base digit is found.
- */
- static void
- scan_number(base)
- int base;
- {
- int result;
-
- TRACECH("scan_number");
-
- t_value = 0;
- while ( (result = is_base_digit(base)) != -1) {
- t_value = ((long)base * t_value) + (long) result;
- sysnext();
- }
-
- LEAVE("scan_number");
- }
-
- /*
- Output a comment. Allow nested comments if nest_flag is TRUE.
- Surprisingly, this routine needs to be as fast as possible.
- */
- void
- copy_comment()
- {
- register int clevel;
- int start_line;
- char line [LONG_DIGITS];
-
- TRACECH("copy_comment");
-
- /* Save starting line number for run-on comments. */
- start_line = t_line;
- clevel = 1;
-
- for (;;) {
- switch (ch) {
-
- case END_FILE:
- conv2s(start_line, line);
- err3("File ends in a comment starting at line ",
- line, ".");
- RETURN_VOID("copy_comment");
-
- case '\n':
- /* Keep track of line numbering. */
- bump_line();
- sysnlput();
- sysnext();
- continue;
-
- case '/':
-
- syscput(ch);
- sysnext();
- if (ch == '*') {
- syscput(ch);
- sysnext();
- if (nest_flag) {
- clevel++;
- }
- }
- continue;
-
- case '*':
- syscput(ch);
- sysnext();
- if (ch == '/') {
- syscput(ch);
- sysnext();
- if (--clevel == 0) {
- RETURN_VOID("copy_comment");
- }
- }
- continue;
-
-
- default:
- syscput(ch);
- sysnext();
- }
- }
- }
-
- void
- skip_comment()
- {
- register int clevel;
- int start_line;
- char line [LONG_DIGITS];
-
- TRACECH("skip_comment");
-
- /* Save starting line number for run-on comments. */
- start_line = t_line;
- clevel = 1;
-
- for (;;) {
- switch (ch) {
-
- case END_FILE:
- conv2s(start_line, line);
- err3("File ends in a comment starting at line ",
- line, ".");
- RETURN_VOID("skip_comment");
-
- case EORT:
- conv2s(start_line, line);
- err3("Macro arg ends in a comment starting at line ",
- line, ".");
- RETURN_VOID("skip_comment");
-
-
- case '\n':
- /* Keep track of line numbering. */
- bump_line();
- sysnext();
- continue;
-
- case '/':
- sysnext();
- if (ch == '*') {
- sysnext();
- if (nest_flag) {
- clevel++;
- }
- }
- continue;
-
- case '*':
- sysnext();
- if (ch == '/') {
- sysnext();
- if (--clevel == 0) {
- RETURN_VOID("skip_comment");
- }
- }
- continue;
-
- default:
- sysnext();
- }
- }
- }
-
- /*
- Copy an identifier into symbol[] and its length in the global t_length.
- Surprisingly, this routine should be as fast as possible.
- */
- void
- t_id(symbol, max_length)
- char * symbol;
- int max_length;
- {
- int length = 0;
-
- TRACEPB("t_id", printf("(%p, %d)\n", symbol, max_length));
-
- max_length--;
- while (isid2(ch) && length < max_length) {
- *symbol++ = ch;
- length++;
- sysnext();
- }
- *symbol = '\0';
- t_length = length;
-
- if (length >= max_length) {
- error("Identifier too long.");
- }
-
- LEAVE("t_id");
- }
-
- /*
- Parse an integer constant (octal, decimal or hexadecimal) or float.
- Put the value in t_value if it is an integer.
-
- dot_flag is TRUE if a decimal point has been seen.
-
- Return the token type (INT_TOK, LONG_TOK, FLOAT_TOK).
-
- Legal integer forms: ddd, 0ddd, 0xddd
- Legal float forms: xxx.yyyE+zzz
-
- +-zzz is optional
- one of xxx and yyy may be omitted
- one of . and E may be omitted
- */
- en_tokens
- t_number(dot_flag)
- bool dot_flag;
- {
- en_tokens result;
- bool need_exp = FALSE;
-
- TRACECH("t_number");
-
- /* Defaults. */
- t_value = 0;
-
- if (dot_flag) {
- goto frac_part;
- }
-
- /* Integer part. */
-
- result = t_int();
- if (ch == '.') {
- sysnext();
- goto frac_part;
- }
- else if (ch == 'e' || ch == 'E') {
- goto exp_part;
- }
- else {
- RETURN_INT("t_number", result);
- }
-
- /* Fraction part. */
- frac_part:
- t_int();
-
- exp_part:
- if (ch == 'e' || ch == 'E') {
- need_exp = TRUE;
- sysnext();
- }
- if (ch == '+' || ch == '-') {
- need_exp = TRUE;
- sysnext();
- }
- if (ch >= '0' && ch <= '9') {
- t_int();
- }
- else if (need_exp) {
- error("Ill formed floating constant.");
- }
-
- if (ch == 'l' || ch == 'L' || ch == 'f' || ch == 'F') {
- sysnext();
- }
-
- RETURN_INT("t_number", FLOAT_TOK);
- }
-
- static en_tokens
- t_int()
- {
- TRACECH("t_int");
-
- /* Leading 0 or 0x changes base. */
- if (ch == '0') {
- sysnext();
- if (ch == 'x' || ch == 'X') {
- sysnext();
- scan_number(16);
- }
- else if (isdigit(ch)) {
- scan_number(8);
- }
- else {
- /* Lone '0'. */
- t_value = 0;
- }
- }
- else {
- scan_number(10);
- }
-
- if (ch == 'l' || ch == 'L') {
- sysnext();
- if(ch == 'u' || ch == 'U') {
- sysnext();
- }
- RETURN_INT("t_int", LONG_TOK);
- }
- else if (ch == 'u' || ch == 'U') {
- sysnext();
- if (ch == 'l' || ch == 'L') {
- RETURN_INT("t_int", LONG_TOK);
- }
- else {
- RETURN_INT("t_int", INT_TOK);
- }
- }
- else {
- RETURN_INT("t_int", INT_TOK);
- }
- }
-
- /*
- Copy a string into out[] and puts its length in the global t_length.
- Copy the opening or closing delimiters if the copy_flag is TRUE.
-
- This is used to parse both strings and character constants.
- */
- void
- t_string(out, max_out, copy_flag)
- register char * out; /* The output buffer. */
- int max_out; /* The size of out[]. */
- bool copy_flag; /* Copy the delimiters if copy_flag is TRUE. */
- {
- register int length;
- int start_line;
- char * start_string;
- char line [10];
- int delim;
-
- TRACECH("t_string");
-
- /* Save starting line number for error messages. */
- start_line = t_line;
- start_string = out;
-
- /* Handle the opening single or double quote */
- delim = ch;
- sysnext();
- length = 0;
- if (copy_flag) {
- *out++ = delim;
- length++;
- }
-
- max_out--;
- while (length < max_out) {
-
- switch(ch) {
-
- case END_FILE:
- case '\n':
- goto runon1;
-
- case '"':
- case '\'':
- if (ch == delim) {
- sysnext();
- if(copy_flag) {
- *out++ = delim;
- length++;
- }
- *out++ = '\0';
- t_length = length;
- TRACEP("t_string", printf("<%s>\n",
- start_string));
- RETURN_VOID("t_string");
- }
- else{
- *out++ = ch;
- length++;
- sysnext();
- }
- continue;
-
- case '\\':
-
- sysnext();
- if (ch == END_FILE) {
- goto runon1;
- }
- else if (ch == '\n') {
- /* Ignore back slash and newline. */
- t_line++;
- sysnext();
- }
- else {
- *out++ = '\\';
- *out++ = ch;
- length += 2;
- sysnext();
- }
- continue;
-
- default:
- *out++ = ch;
- length++;
- sysnext();
- }
- }
-
- conv2s(start_line, line);
- err3("String starting at line ", line, " is too long.");
-
- *out = '\0';
- t_length = length;
- RETURN_VOID("t_string");
-
- runon1:
- *out = '\0';
- err2("String crosses a line: ", start_string);
- t_length = length;
- LEAVE("t_string");
- }
-
- /*
- Parse a string (including delimiters) from in[] to out.
- Return the length of the ORIGINAL string.
- */
- int
- in_string(in, out, max_out)
- char * in; /* The output buffer */
- char * out; /* The output buffer. */
- int max_out; /* The size of out[]. */
- {
- register int length;
- int start_line;
- char * start_string;
- char line [10];
- int delim;
-
- TRACEPB("in_string", printf("(<%s>, %p, %d)\n",
- in, out, max_out));
-
- /* Save starting line number for error messages. */
- start_line = t_line;
- start_string = out;
-
- /* Copy the opening single or double quote */
- *out++ = delim = *in++;
- length = 1;
- max_out--;
- while (length < max_out) {
-
- switch(*in) {
-
- case END_FILE:
- case '\n':
- goto runon1;
-
- case '"':
- case '\'':
- if (*in == delim) {
- *out++ = *in++;
- *out++ = '\0';
- length++;
- RETURN_INT("in_string", length);
- }
- else{
- *out++ = *in++;
- length++;
- }
- continue;
-
- case '\\':
-
- in++;
- if (*in == END_FILE) {
- goto runon1;
- }
- else if (*in == '\n') {
- /* Ignore back slash and newline. */
- t_line++;
- in++;
-
- /* Keep track of ORIGINAL length. */
- length += 2;
- }
- else {
- *out++ = '\\';
- *out++ = *in++;
- length += 2;
- }
- continue;
-
- default:
- *out++ = *in++;
- length++;
- }
- }
-
- conv2s(start_line, line);
- err3("Strinized argument starting at line ", line, " is too long.");
- *out = '\0';
- RETURN_INT("in_string", length);
-
- runon1:
- *out = '\0';
- err2("Stringized argument crosses a line: ", start_string);
- RETURN_INT("in_string", length);
- }
-